#pragma once
#include <memory>
#include <type_traits>
#include <vector>
namespace lcir {
/// OwnRefVector是对std::vector的一个封装，由vector掌管内部元素生命周期，并向外提供引用访问
/// 由于对std::vector容器内部的迭代器会在扩容时失效，值地址改变
/// 有对应需求（需要vector掌握元素生命周期）应当使用OwnRefVector
/// 迭代器直接在C++ vector迭代器基础上封装
/// TODO: 迭代器暂不兼容stl算法
template <class Ty, bool IsConst>
struct STLIteratorTrait;
template <class Ty>
struct STLIteratorTrait<Ty, true> {
  using type = typename std::vector<std::unique_ptr<Ty>>::const_iterator;
  using pointer = const Ty *;
  using reference = const Ty &;
};
template <class Ty>
struct STLIteratorTrait<Ty, false> {
  using type = typename std::vector<std::unique_ptr<Ty>>::iterator;
  using pointer = Ty *;
  using reference = Ty &;
};

template <class Ty, bool IsConst>
class OwningRefVecIterator {
  friend class OwningRefVecIterator<Ty, !IsConst>;
  using trait = STLIteratorTrait<Ty, IsConst>;
  using stlItTy = typename trait::type;
  using itTy = OwningRefVecIterator<Ty, IsConst>;
  stlItTy it;

 public:
  using pointer = typename trait::pointer;
  using reference = typename trait::reference;
  OwningRefVecIterator(stlItTy it) : it(it) {}
  // 拷贝构造，可以将常量迭代器指向非常量迭代器
  template <bool rhsIsConst>
  OwningRefVecIterator(const OwningRefVecIterator<Ty, rhsIsConst> &rhs,
                       std::enable_if_t<IsConst || !rhsIsConst, void *> = nullptr)
      : it(rhs.it) {}
  /// 拷贝赋值，可以将常量迭代器指向非常量迭代器
  template <bool rhsIsConst>
  std::enable_if_t<IsConst || !rhsIsConst, OwningRefVecIterator &> operator=(
      const OwningRefVecIterator<Ty, rhsIsConst> &rhs) {
    it = rhs.it;
    return *this;
  }
  Ty &operator*() const { return **it; }
  stlItTy operator->() const { return it; }
  itTy &operator++() {
    ++it;
    return *this;
  }
  itTy &operator--() {
    --it;
    return *this;
  }
  itTy operator++(int) {
    auto temp = *this;
    ++it;
    return temp;
  }
  itTy &operator--(int) {
    auto temp = *this;
    --it;
    return temp;
  }
  friend bool operator==(const itTy &lhs, const itTy &rhs) { return lhs.it == rhs.it; }
  friend bool operator!=(const itTy &lhs, const itTy &rhs) { return lhs.it != rhs.it; }
};
template <class Ty>
class OwningRefVector {
  using iterator = OwningRefVecIterator<Ty, false>;
  using constIterator = OwningRefVecIterator<Ty, true>;
  std::vector<std::unique_ptr<Ty>> v;

 public:
  OwningRefVector() = default;
  OwningRefVector(const OwningRefVector &) = delete;
  OwningRefVector(OwningRefVector &&) = delete;
  OwningRefVector &operator()(OwningRefVector &&) = delete;
  OwningRefVector &operator()(const OwningRefVector &) = delete;
  void pushBack(Ty *ptr) { v.push_back(std::unique_ptr<Ty>(ptr)); }
  Ty &operator[](size_t n) const { return *v[n]; }
  Ty &operator[](size_t n) { return *v[n]; }
  constIterator begin() const { return constIterator(v.begin()); }
  constIterator end() const { return constIterator(v.end()); }
  iterator begin() { return iterator(v.begin()); }
  iterator end() { return iterator(v.end()); }
  Ty &back() { return *v.back(); }
  size_t size() const { return v.size(); }
  bool empty() const { return v.empty(); }
  std::vector<Ty *> getVector() const {
    std::vector<Ty *> ret;
    for (auto &ptr : v) ret.push_back(ptr.get());
    return ret;
  }
};
}  // namespace lcir